﻿using AutoMapper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using StarsAdmin.Application.Menu.Dtos;
using StarsAdmin.Core.Cache;
using StarsAdmin.Core.Consts;
using StarsAdmin.Core.DB.Entities;
using StarsAdmin.Core.Enums;
using StarsAdmin.Core.Exceptions;
using StarsAdmin.Core.Extensions;
using StarsAdmin.Core.Models;
using StarsAdmin.Repository.Api;
using StarsAdmin.Repository.Menu;

namespace StarsAdmin.Application.Menu.Services
{
    public class MenuService : IMenuService
    {
        private readonly IMapper _mapper;
        private readonly ICacheService _cache;
        private readonly IMenuRepository _menuRepository;
        private readonly IApiRepository _apiRepository;
        private readonly IWebHostEnvironment _webHostEnvironment;

        public MenuService(IMapper mapper, ICacheService cacheService, IMenuRepository menuRepository, IApiRepository apiRepository, IWebHostEnvironment webHostEnvironment)
        {
            _mapper = mapper;
            _cache = cacheService;
            _menuRepository = menuRepository;
            _apiRepository = apiRepository;
            _webHostEnvironment = webHostEnvironment;
        }

        #region 查询

        public async Task<List<MenuDto>> GetAllAsync(BaseQueryInput input)
        {
            var result = await _menuRepository.GetAll()
                         .AsNoTracking()
                         .WhereIf(input != null && input.QueryConditions.Any(), input.QueryConditions)
                         .OrderBy(e => e.Sort)
                         .Include(e => e.Apis)
                         .Include(e => e.Parent)
                         .ToTreeAsync();
            return _mapper.Map<List<MenuDto>>(result);
        }

        public async Task<Page<MenuDto>> GetPageAsync(PageQueryInput input)
        {
            var result = await _menuRepository.GetAll().AsNoTracking()
                               .WhereIf(input != null && input.QueryConditions.Any(), input.QueryConditions)
                               .OrderByIf(input != null && input.Sort != null, input.Sort, input.Order != false)
                               .ToPageListAsync(input.CurrentPage, input.PageSize);
            return _mapper.Map<Page<MenuDto>>(result);
        }

        public async Task<MenuDto?> GetByIdAsync(long id)
        {
            var result = await _menuRepository.GetById(id).Include(e => e.Parent).FirstOrDefaultAsync();
            return _mapper.Map<MenuDto>(result);
        }

        public async Task<List<MenuDto>> GetByIdsAsync(long[] ids)
        {
            var result = await _menuRepository.GetByIds(ids).ToListAsync();
            return _mapper.Map<List<MenuDto>>(result);
        }

        #endregion 查询

        #region 导入导出

        public async Task<FileContentResult?> ExportTemplateAsync()
        {
            var filePath = "template/菜单管理.xlsx";
            var localPath = _webHostEnvironment.WebRootPath.CombineAndFormatPath(filePath);
            // 检查文件是否存在
            if (!System.IO.File.Exists(localPath))
            {
                throw new NotFoundException("未找到指定的模版文件。");
            }
            return await FileExtension.ExportExcelFileAsync(localPath);
        }

        public async Task<FileContentResult?> ExportAsync(long[] ids)
        {
            var export = await _menuRepository.GetByIds(ids).Include(e => e.Parent).ToListAsync();
            return await _mapper.Map<List<ExportMenuDto>>(export).ToExcelAsync("菜单管理");
        }

        public async Task<bool> ImportAsync(List<AddMenuInput> inputs)
        {
            var entities = _mapper.Map<List<MenuEntity>>(inputs);
            var apiIds = inputs.SelectMany(e => e.ApiIds ?? []).ToList();
            if (apiIds != null && apiIds.Count != 0)
            {
                var apis = await _apiRepository.GetByIdsAsync(apiIds);
                if (apis == null || !apis.Any())
                {
                    throw new NotFoundException("未找到指定的菜单权限。");
                }
                foreach (var entity in entities)
                {
                    if (entity.ApiIds != null && entity.ApiIds.Length != 0)
                    {
                        entity.Apis = apis.Where(e => entity.ApiIds.Contains(e.Id)).ToList();
                    }
                }
            }
            var result = await _menuRepository.AddRangeAndSaveAsync(entities);
            if (result)
            {
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        #endregion 导入导出

        #region 添加

        public async Task<bool> AddAsync(AddMenuInput input)
        {
            var entity = _mapper.Map<MenuEntity>(input);
            if (input.ApiIds != null && input.ApiIds.Length > 0)
            {
                var apis = await _apiRepository.GetByIdsAsync(input.ApiIds);
                if (apis == null || !apis.Any())
                {
                    throw new NotFoundException("未找到指定的接口。");
                }
                entity.Apis.Clear();
                entity.Apis = await apis.ToListAsync();
            }
            var result = await _menuRepository.AddAndSaveAsync(entity);
            if (result)
            {
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        #endregion 添加

        #region 更新

        public async Task<bool> AssignPermissionsAsync(AssignPermissionsInput input)
        {
            var entity = await _menuRepository.GetById(input.Id).Include(e => e.Apis).FirstOrDefaultAsync();
            if (entity == null)
            {
                throw new NotFoundException("未找到指定的菜单。");
            }
            var apis = await _apiRepository.GetByIdsAsync(input.Ids);
            if (apis == null || !apis.Any())
            {
                throw new NotFoundException("未找到指定的接口。");
            }
            entity.Apis.Clear();
            entity.Apis = await apis.ToListAsync();
            var result = await _menuRepository.UpdateAndSaveAsync(entity);
            if (result)
            {
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        public async Task<bool> UpdateAsync(UpdateMenuInput input)
        {
            var menu = await _menuRepository.GetByIdAsync(input.Id);
            if (menu == null)
            {
                throw new NotFoundException("未找到指定的菜单。");
            }
            var entity = _mapper.Map(input, menu);
            if (input.ApiIds != null && input.ApiIds.Length != 0)
            {
                var apis = await _apiRepository.GetByIdsAsync(input.ApiIds);
                if (apis == null || !apis.Any())
                {
                    throw new NotFoundException("未找到指定的接口。");
                }
                entity.Apis.Clear();
                entity.Apis = await apis.ToListAsync();
            }
            var result = await _menuRepository.UpdateAndSaveAsync(entity);
            if (result)
            {
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        public async Task<bool> SortableAsync(long id, long targetId)
        {
            if (id == targetId)
            {
                throw new InUseException("目标位置与当前位置相同。");
            }
            var currentEntity = await _menuRepository.GetByIdAsync(id);
            if (currentEntity == null)
            {
                throw new NotFoundException("当前菜单未找到。");
            }
            var targetEntity = await _menuRepository.GetByIdAsync(targetId);
            if (targetEntity == null)
            {
                throw new NotFoundException("目标菜单未找到。");
            }
            // 只能兄弟之间移动
            if (currentEntity.ParentId != targetEntity.ParentId)
            {
                throw new InUseException("移动位置超出了可移动范围。");
            }
            // 查找所有兄弟
            var brother = await _menuRepository.GetBy(e => e.ParentId == currentEntity.ParentId, false).ToListAsync();
            // 移动范围内的兄弟
            var brotherRange = new List<MenuEntity>();
            // 目标位置顺序号
            var targetIndex = targetEntity.Sort;
            if (currentEntity.Sort > targetEntity.Sort)
            {
                // 往前移动
                brotherRange = brother.Where(e => e.Sort >= targetEntity.Sort && e.Sort <= currentEntity.Sort).ToList();
                foreach (var item in brotherRange)
                {
                    if (item.Id == currentEntity.Id)
                    {
                        item.Sort = targetIndex;
                    } else
                    {
                        item.Sort = item.Sort + 1;
                    }
                }
            } else if (currentEntity.Sort < targetEntity.Sort)
            {
                // 往后移动
                brotherRange = brother.Where(e => e.Sort <= targetEntity.Sort && e.Sort >= currentEntity.Sort).ToList();
                foreach (var item in brotherRange)
                {
                    if (item.Id == currentEntity.Id)
                    {
                        item.Sort = targetIndex;
                    } else
                    {
                        item.Sort = item.Sort - 1;
                    }
                }
            }
            var result = await _menuRepository.UpdateRangeAndSaveAsync(brotherRange);
            if (result)
            {
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        public async Task<bool> EnabledAsync(long id)
        {
            var entity = await _menuRepository.GetByIdAsync(id);
            if (entity == null)
            {
                throw new NotFoundException("未找到指定的菜单。");
            }
            entity.IsEnabled = !entity.IsEnabled;
            var result = await _menuRepository.UpdateAndSaveAsync(entity);
            if (result)
            {
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        #endregion 更新

        #region 删除

        public async Task<bool> DeleteAsync(long id)
        {
            var entity = await _menuRepository.GetById(id).Include(e => e.Apis).FirstOrDefaultAsync();
            if (entity == null)
            {
                throw new NotFoundException("未找到指定的菜单。");
            }
            if (entity.Roles.Count > 0)
            {
                throw new InUseException($"{entity.Title}菜单已经分配给角色，无法删除。");
            }
            var result = await _menuRepository.DeleteAsync(entity.Id);
            if (result)
            {
                entity.Apis.Clear();
                await _menuRepository.SaveChangesAsync();
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        public async Task<bool> BatchDeleteAsync(long[] ids)
        {
            var entities = await _menuRepository.GetByIds(ids).Include(e => e.Apis).ToListAsync();
            if (entities == null || entities.Count < 1)
            {
                throw new NotFoundException("未找到指定的菜单。");
            }
            _ = entities.Any(e =>
            {
                if (e.Roles.Count > 0)
                {
                    throw new InUseException($"{e.Title}菜单已经分配给角色，无法删除。");
                }
                return true;
            });
            var result = await _menuRepository.DeleteRangeAsync(ids);
            if (result)
            {
                foreach (var entity in entities)
                {
                    entity?.Apis.Clear();
                }
                await _menuRepository.SaveChangesAsync();
                await _cache.RemoveAsync(CacheKeyConst.MenuCacheKey);
            }
            return result;
        }

        #endregion 删除
    }
}